home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / IP.C < prev    next >
C/C++ Source or Header  |  1997-09-07  |  15KB  |  582 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "netuser.h"
  11. #include "iface.h"
  12. #include "pktdrvr.h"
  13. #include "icmp.h"
  14. #include "commands.h"
  15.  
  16. #if !defined(_lint)
  17. static char rcsid[] OPTIONAL = "$Id: ip.c,v 1.18 1997/09/07 21:18:28 root Exp root $";
  18. #endif
  19.  
  20. static struct mbuf *fraghandle (struct ip * ip, struct mbuf * bp);
  21. static void ip_timeout (void *arg);
  22. static void free_reasm (struct reasm * rp);
  23. static void freefrag (struct frag * fp);
  24. static struct reasm *lookup_reasm (struct ip * ip);
  25. static struct reasm *creat_reasm (struct ip * ip);
  26. static struct frag *newfrag (int16 offset, int16 last, struct mbuf * bp);
  27.  
  28. struct mib_entry Ip_mib[20] =
  29. {
  30.     { "",            {0} },
  31.     { "ipForwarding",    {1} },
  32.     { "ipDefaultTTL",    {MAXTTL} },
  33.     { "ipInReceives",    {0} },
  34.     { "ipInHdrErrors",    {0} },
  35.     { "ipInAddrErrors",    {0} },
  36.     { "ipForwDatagrams",    {0} },
  37.     { "ipInUnknownProtos",    {0} },
  38.     { "ipInDiscards",    {0} },
  39.     { "ipInDelivers",    {0} },
  40.     { "ipOutRequests",    {0} },
  41.     { "ipOutDiscards",    {0} },
  42.     { "ipOutNoRoutes",    {0} },
  43.     { "ipReasmTimeout",    {TLB} },
  44.     { "ipReasmReqds",    {0} },
  45.     { "ipReasmOKs",        {0} },
  46.     { "ipReasmFails",    {0} },
  47.     { "ipFragOKs",        {0} },
  48.     { "ipFragFails",    {0} },
  49.     { "ipFragCreates",    {0} },
  50. };
  51.  
  52.  
  53. struct reasm *Reasmq;
  54. static struct raw_ip *Raw_ip = NULLRIP;
  55. static int raw_ip_inuse = TNOS_MUTEX_UNLOCKED;
  56.  
  57. #define    INSERT    0
  58. #define    APPEND    1
  59. #define    PREPEND    2
  60.  
  61.  
  62.  
  63. /* Send an IP datagram. Modeled after the example interface on p 32 of
  64.  * RFC 791
  65.  */
  66. int
  67. ip_send (source, dest, protocol, tos, ttl, bp, length, id, df)
  68. uint32 source;            /* source address */
  69. uint32 dest;            /* Destination address */
  70. char protocol;            /* Protocol */
  71. char tos;            /* Type of service */
  72. char ttl;            /* Time-to-live */
  73. struct mbuf *bp;        /* Data portion of datagram */
  74. int16 length;            /* Optional length of data portion */
  75. int16 id;            /* Optional identification */
  76. char df;            /* Don't-fragment flag */
  77. {
  78. struct mbuf *tbp;
  79. struct ip ip;        /* IP header */
  80. static int16 id_cntr = 0;    /* Datagram serial number */
  81. struct phdr phdr;
  82.  
  83.     ipOutRequests++;
  84.  
  85.     if (source == INADDR_ANY)
  86.         source = locaddr (dest);
  87.     if (length == 0 && bp != NULLBUF)
  88.         length = len_p (bp);
  89.     if (id == 0)
  90.         id = id_cntr++;
  91.     if (ttl == 0)
  92.         ttl = (char) ipDefaultTTL;
  93.  
  94.     /* Fill in IP header */
  95.     ip.version = IPVERSION;
  96.     ip.tos = tos;
  97.     ip.length = IPLEN + length;
  98.     ip.id = id;
  99.     ip.offset = 0;
  100.     ip.flags.mf = 0;
  101.     ip.flags.df = df;
  102.     ip.flags.congest = 0;
  103.     ip.ttl = ttl;
  104.     ip.protocol = protocol;
  105.     ip.source = source;
  106.     ip.dest = dest;
  107.     ip.optlen = 0;
  108.     if ((tbp = htonip (&ip, bp, IP_CS_NEW)) == NULLBUF) {
  109.         free_p (bp);
  110.         return -1;
  111.     }
  112.     if ((bp = pushdown (tbp, sizeof (phdr))) == NULLBUF) {
  113.         free_p (tbp);
  114.         return -1;
  115.     }
  116.     if (ismyaddr (ip.dest)) {
  117.         /* Pretend it has been sent by the loopback interface before
  118.          * it appears in the receive queue
  119.          */
  120.         phdr.iface = &Loopback;
  121.         Loopback.ipsndcnt++;
  122.         Loopback.rawsndcnt++;
  123.         Loopback.lastsent = secclock ();
  124.     } else
  125.         phdr.iface = NULLIF;
  126.     phdr.type = CL_NONE;
  127.     memcpy (&bp->data[0], (char *) &phdr, sizeof (phdr));
  128.     enqueue (&Hopper, bp);
  129.     return 0;
  130. }
  131.  
  132.  
  133.  
  134. /* Reassemble incoming IP fragments and dispatch completed datagrams
  135.  * to the proper transport module
  136.  */
  137. void
  138. ip_recv (iface, ip, bp, rxbroadcast)
  139. struct iface *iface;        /* Incoming interface */
  140. struct ip *ip;            /* Extracted IP header */
  141. struct mbuf *bp;        /* Data portion */
  142. int rxbroadcast;        /* True if received on subnet broadcast address */
  143. {
  144. /* Function to call with completed datagram */
  145. register struct raw_ip *rp;
  146. struct mbuf *bp1, *tbp;
  147. int rxcnt = 0;
  148. register struct iplink *ipp;
  149.  
  150.     /* If we have a complete packet, call the next layer
  151.      * to handle the result. Note that fraghandle passes back
  152.      * a length field that does NOT include the IP header
  153.      */
  154.     if ((bp = fraghandle (ip, bp)) == NULLBUF)
  155.         return;        /* Not done yet */
  156.  
  157.     ipInDelivers++;
  158.  
  159.     kmutex_lock (&raw_ip_inuse);
  160.  
  161.     for (rp = Raw_ip; rp != NULLRIP; rp = rp->next) {
  162.         if (rp->protocol != ip->protocol)
  163.             continue;
  164.         rxcnt++;
  165.         /* Duplicate the data portion, and put the header back on */
  166.         (void) dup_p (&bp1, bp, 0, len_p (bp));
  167.         if (bp1 != NULLBUF && (tbp = htonip (ip, bp1, IP_CS_OLD)) != NULLBUF) {
  168.             enqueue (&rp->rcvq, tbp);
  169.             if (rp->r_upcall != NULLVFP ((struct raw_ip *)))
  170.                 (*rp->r_upcall) (rp);
  171.         } else {
  172.             free_p (bp1);
  173.         }
  174.     }
  175.     kmutex_unlock (&raw_ip_inuse);
  176.     
  177.     /* Look it up in the transport protocol table */
  178.     for (ipp = Iplink; ipp->funct != NULL; ipp++) {
  179.         if (ipp->proto == ip->protocol)
  180.             break;
  181.     }
  182.     if (ipp->funct != NULL) {
  183.         /* Found, call transport protocol */
  184.         (*ipp->funct) (iface, ip, bp, rxbroadcast);
  185.     } else {
  186.         /* Not found */
  187.         if (rxcnt == 0) {
  188.             /* Send an ICMP Protocol Unknown response... */
  189.             ipInUnknownProtos++;
  190.             /* ...unless it's a broadcast */
  191.             if (!rxbroadcast)
  192.                 (void) icmp_output (ip, bp, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, NULLICMP);
  193.         }
  194.         free_p (bp);
  195.     }
  196. }
  197.  
  198.  
  199.  
  200. #ifdef ENCAP
  201. /* Handle IP packets encapsulated inside IP */
  202. void
  203. ipip_recv (iface, ip, bp, rxbroadcast)
  204. struct iface *iface OPTIONAL;    /* Incoming interface */
  205. struct ip *ip OPTIONAL;        /* Extracted IP header */
  206. struct mbuf *bp;        /* Data portion */
  207. int rxbroadcast OPTIONAL;    /* True if received on subnet broadcast address */
  208. {
  209. struct phdr phdr;
  210. struct mbuf *tbp;
  211.  
  212.     if ((tbp = pushdown (bp, sizeof (phdr))) == NULLBUF) {
  213.         free_p (bp);
  214.         return;
  215.     }
  216.     bp = tbp;
  217.     phdr.iface = &Encap;
  218.     phdr.type = CL_NONE;
  219.     memcpy (&bp->data[0], (char *) &phdr, sizeof (phdr));
  220.     enqueue (&Hopper, bp);
  221. }
  222. #endif
  223.  
  224.  
  225.  
  226. /* Process IP datagram fragments
  227.  * If datagram is complete, return it with ip->length containing the data
  228.  * length (MINUS header); otherwise return NULLBUF
  229.  */
  230. static
  231. struct mbuf *
  232. fraghandle (ip, bp)
  233. struct ip *ip;            /* IP header, host byte order */
  234. struct mbuf *bp;        /* The fragment itself */
  235. {
  236. register struct reasm *rp;    /* Pointer to reassembly descriptor */
  237. struct frag *lastfrag, *nextfrag, *tfp;
  238. struct mbuf *tbp;
  239. int16 i;
  240. int16 last;        /* Index of first byte beyond fragment */
  241.  
  242.     last = (int16) (ip->offset + ip->length - (IPLEN + ip->optlen));
  243.  
  244.     rp = lookup_reasm (ip);
  245.     if (ip->offset == 0 && !ip->flags.mf) {
  246.         /* Complete datagram received. Discard any earlier fragments */
  247.         if (rp != NULLREASM) {
  248.             free_reasm (rp);
  249.             ipReasmOKs++;
  250.         }
  251.         return bp;
  252.     }
  253.     ipReasmReqds++;
  254.     if (rp == NULLREASM) {
  255.         /* First fragment; create new reassembly descriptor */
  256.         if ((rp = creat_reasm (ip)) == NULLREASM) {
  257.             /* No space for descriptor, drop fragment */
  258.             ipReasmFails++;
  259.             free_p (bp);
  260.             return NULLBUF;
  261.         }
  262.     }
  263.     /* Keep restarting timer as long as we keep getting fragments */
  264.     start_detached_timer (&rp->timer);
  265.  
  266.     /* If this is the last fragment, we now know how long the
  267.      * entire datagram is; record it
  268.      */
  269.     if (!ip->flags.mf)
  270.         rp->length = last;
  271.  
  272.     /* Set nextfrag to the first fragment which begins after us,
  273.      * and lastfrag to the last fragment which begins before us
  274.      */
  275.     lastfrag = NULLFRAG;
  276.     for (nextfrag = rp->fraglist; nextfrag != NULLFRAG; nextfrag = nextfrag->next) {
  277.         if (nextfrag->offset > ip->offset)
  278.             break;
  279.         lastfrag = nextfrag;
  280.     }
  281.     /* Check for overlap with preceeding fragment */
  282.     if (lastfrag != NULLFRAG && ip->offset < lastfrag->last) {
  283.         /* Strip overlap from new fragment */
  284.         i = lastfrag->last - ip->offset;
  285.         (void) pullup (&bp, (unsigned char *) 0, i);
  286.         if (bp == NULLBUF)
  287.             return NULLBUF;    /* Nothing left */
  288.         ip->offset += i;
  289.     }
  290.     /* Look for overlap with succeeding segments */
  291.     for (; nextfrag != NULLFRAG; nextfrag = tfp) {
  292.         tfp = nextfrag->next;    /* save in case we delete fp */
  293.  
  294.         if (nextfrag->offset >= last)
  295.             break;    /* Past our end */
  296.         /* Trim the front of this entry; if nothing is
  297.          * left, remove it.
  298.          */
  299.         i = last - nextfrag->offset;
  300.         (void) pullup (&nextfrag->buf, (unsigned char *) 0, i);
  301.         if (nextfrag->buf == NULLBUF) {
  302.             /* superseded; delete from list */
  303.             if (nextfrag->prev != NULLFRAG)
  304.                 nextfrag->prev->next = nextfrag->next;
  305.             else
  306.                 rp->fraglist = nextfrag->next;
  307.             if (tfp->next != NULLFRAG)
  308.                 nextfrag->next->prev = nextfrag->prev;
  309.             freefrag (nextfrag);
  310.         } else
  311.             nextfrag->offset = last;
  312.     }
  313.     /* Lastfrag now points, as before, to the fragment before us;
  314.      * nextfrag points at the next fragment. Check to see if we can
  315.      * join to either or both fragments.
  316.      */
  317.     i = INSERT;
  318.     if (lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  319.         i |= APPEND;
  320.     if (nextfrag != NULLFRAG && nextfrag->offset == last)
  321.         i |= PREPEND;
  322.     /*lint -save -e613 */
  323.     switch (i) {
  324.         case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  325.             tfp = newfrag (ip->offset, last, bp);
  326.             tfp->prev = lastfrag;
  327.             tfp->next = nextfrag;
  328.             if (lastfrag != NULLFRAG)
  329.                 lastfrag->next = tfp;    /* Middle of list */
  330.             else
  331.                 rp->fraglist = tfp;    /* First on list */
  332.             if (nextfrag != NULLFRAG)
  333.                 nextfrag->prev = tfp;
  334.             break;
  335.         case APPEND:    /* Append to lastfrag */
  336.             append (&lastfrag->buf, bp);
  337.             lastfrag->last = last;    /* Extend forward */
  338.             break;
  339.         case PREPEND:    /* Prepend to nextfrag */
  340.             tbp = nextfrag->buf;
  341.             nextfrag->buf = bp;
  342.             append (&nextfrag->buf, tbp);
  343.             nextfrag->offset = ip->offset;    /* Extend backward */
  344.             break;
  345.         case (APPEND | PREPEND):
  346.             /* Consolidate by appending this fragment and nextfrag
  347.              * to lastfrag and removing the nextfrag descriptor
  348.              */
  349.             append (&lastfrag->buf, bp);
  350.             append (&lastfrag->buf, nextfrag->buf);
  351.             nextfrag->buf = NULLBUF;
  352.             lastfrag->last = nextfrag->last;
  353.  
  354.             /* Finally unlink and delete the now unneeded nextfrag */
  355.             lastfrag->next = nextfrag->next;
  356.             if (nextfrag->next != NULLFRAG)
  357.                 nextfrag->next->prev = lastfrag;
  358.             freefrag (nextfrag);
  359.             break;
  360.         default:
  361.             break;
  362.     }
  363.     /*lint -restore */
  364.     if (rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG && rp->length != 0) {
  365.         /* We've gotten a complete datagram, so extract it from the
  366.          * reassembly buffer and pass it on.
  367.          */
  368.         bp = rp->fraglist->buf;
  369.         rp->fraglist->buf = NULLBUF;
  370.         /* Tell IP the entire length */
  371.         ip->length = (int16) (rp->length + (IPLEN + ip->optlen));
  372.         free_reasm (rp);
  373.         ipReasmOKs++;
  374.         return bp;
  375.     } else
  376.         return NULLBUF;
  377. }
  378.  
  379.  
  380.  
  381. /* Arrange for receipt of raw IP datagrams */
  382. struct raw_ip *
  383. raw_ip (protocol, r_upcall)
  384. int protocol;
  385. void (*r_upcall) (struct raw_ip *);
  386. {
  387. register struct raw_ip *rp;
  388.  
  389.     rp = (struct raw_ip *) callocw (1, sizeof (struct raw_ip));
  390.  
  391.     kmutex_lock (&raw_ip_inuse);
  392.     
  393.     rp->protocol = protocol;
  394.     rp->r_upcall = r_upcall;
  395.  
  396.     rp->next = Raw_ip;
  397.     Raw_ip = rp;
  398.     kmutex_unlock (&raw_ip_inuse);
  399.     return rp;
  400. }
  401.  
  402.  
  403.  
  404. /* Free a raw IP descriptor */
  405. void
  406. del_ip (struct raw_ip *rpp)
  407. {
  408. struct raw_ip *rplast = NULLRIP;
  409. register struct raw_ip *rp;
  410.  
  411.     /* Do sanity check on arg */
  412.     for (rp = Raw_ip; rp != NULLRIP; rplast = rp, rp = rp->next)
  413.         if (rp == rpp)
  414.             break;
  415.     if (rp == NULLRIP)
  416.         return;        /* Doesn't exist */
  417.  
  418.     kmutex_lock (&raw_ip_inuse);
  419.  
  420.     /* Unlink */
  421.     if (rplast != NULLRIP)
  422.         rplast->next = rp->next;
  423.     else
  424.         Raw_ip = rp->next;
  425.     kmutex_unlock (&raw_ip_inuse);
  426.  
  427.     /* Free resources */
  428.     free_q (&rp->rcvq);
  429.     free ((char *) rp);
  430. }
  431.  
  432.  
  433.  
  434. static struct reasm *
  435. lookup_reasm (struct ip *ip)
  436. {
  437. register struct reasm *rp;
  438. struct reasm *rplast = NULLREASM;
  439.  
  440.     for (rp = Reasmq; rp != NULLREASM; rplast = rp, rp = rp->next) {
  441.         if (ip->id == rp->id && ip->source == rp->source && ip->dest == rp->dest && ip->protocol == rp->protocol) {
  442.             if (rplast != NULLREASM) {
  443.                 /* Move to top of list for speed */
  444.                 rplast->next = rp->next;
  445.                 rp->next = Reasmq;
  446.                 Reasmq = rp;
  447.             }
  448.             return rp;
  449.         }
  450.     }
  451.     return NULLREASM;
  452. }
  453.  
  454.  
  455.  
  456. /* Create a reassembly descriptor,
  457.  * put at head of reassembly list
  458.  */
  459. static struct reasm *
  460. creat_reasm (register struct ip *ip)
  461. {
  462. register struct reasm *rp;
  463.  
  464.     if ((rp = (struct reasm *) callocw (1, sizeof (struct reasm))) == NULLREASM)
  465.               return rp;/* No space for descriptor */
  466.  
  467.     rp->source = ip->source;
  468.     rp->dest = ip->dest;
  469.     rp->id = ip->id;
  470.     rp->protocol = ip->protocol;
  471.     set_timer (&rp->timer, (long) (ipReasmTimeout * 1000L));
  472.     rp->timer.func = ip_timeout;
  473.     rp->timer.arg = rp;
  474.  
  475.     rp->next = Reasmq;
  476.     Reasmq = rp;
  477.     return rp;
  478. }
  479.  
  480.  
  481.  
  482. /* Free all resources associated with a reassembly descriptor */
  483. static void
  484. free_reasm (struct reasm *r)
  485. {
  486. register struct reasm *rp;
  487. struct reasm *rplast = NULLREASM;
  488. register struct frag *fp;
  489.  
  490.     for (rp = Reasmq; rp != NULLREASM; rplast = rp, rp = rp->next)
  491.         if (r == rp)
  492.             break;
  493.     if (rp == NULLREASM)
  494.         return;        /* Not on list */
  495.  
  496.     stop_timer (&rp->timer);
  497.     /* Remove from list of reassembly descriptors */
  498.     if (rplast != NULLREASM)
  499.         rplast->next = rp->next;
  500.     else
  501.         Reasmq = rp->next;
  502.  
  503.     /* Free any fragments on list, starting at beginning */
  504.     while ((fp = rp->fraglist) != NULLFRAG) {
  505.         rp->fraglist = fp->next;
  506.         free_p (fp->buf);
  507.         free ((char *) fp);
  508.     }
  509.     free ((char *) rp);
  510. }
  511.  
  512.  
  513.  
  514. /* Handle reassembly timeouts by deleting all reassembly resources */
  515. static void
  516. ip_timeout (void *arg)
  517. {
  518. register struct reasm *rp;
  519.  
  520.     rp = (struct reasm *) arg;
  521.     free_reasm (rp);
  522.     ipReasmFails++;
  523. }
  524.  
  525.  
  526.  
  527. /* Create a fragment */
  528. static struct frag *
  529. newfrag (int16 offset, int16 last, struct mbuf *bp)
  530. {
  531. struct frag *fp;
  532.  
  533.     if ((fp = (struct frag *) callocw (1, sizeof (struct frag))) == NULLFRAG) {
  534.         /* Drop fragment */
  535.         free_p (bp);
  536.         return NULLFRAG;
  537.     }
  538.     fp->buf = bp;
  539.     fp->offset = offset;
  540.     fp->last = last;
  541.     return fp;
  542. }
  543.  
  544.  
  545.  
  546. /* Delete a fragment, return next one on queue */
  547. static void
  548. freefrag (struct frag *fp)
  549. {
  550.     free_p (fp->buf);
  551.     free ((char *) fp);
  552. }
  553.  
  554.  
  555.  
  556. #ifdef MSDOS
  557. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  558.  * each fragment on each reassembly descriptor
  559.  */
  560. void
  561. ip_garbage (int red)
  562. {
  563. struct reasm *rp, *rp1;
  564. struct frag *fp;
  565. struct raw_ip *rwp;
  566.  
  567.     /* Run through the reassembly queue */
  568.     for (rp = Reasmq; rp != NULLREASM; rp = rp1) {
  569.         rp1 = rp->next;
  570.         if (red)
  571.             free_reasm (rp);
  572.         else {
  573.             for (fp = rp->fraglist; fp != NULLFRAG; fp = fp->next)
  574.                 mbuf_crunch (&fp->buf);
  575.         }
  576.     }
  577.     /* Run through the raw IP queue */
  578.     for (rwp = Raw_ip; rwp != NULLRIP; rwp = rwp->next)
  579.         mbuf_crunch (&rwp->rcvq);
  580. }
  581. #endif
  582.